package uk.co.hs.web.controller.admin;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.RedirectView;

import uk.co.hs.constants.AdminGeneralConstants;
import uk.co.hs.domain.web.WebForwarding;
import uk.co.hs.domain.web.WebRole;
import uk.co.hs.domain.web.WebUrl;
import uk.co.hs.domain.web.WebUser;
import uk.co.hs.exceptions.DataAccessExceptions;
import uk.co.hs.service.admin.interfaces.WebForwardingServiceInterface;
import uk.co.hs.service.admin.interfaces.WebRoleServiceInterface;
import uk.co.hs.service.admin.interfaces.WebUrlServiceInterface;
import uk.co.hs.service.admin.interfaces.WebUserServiceInterface;
import uk.co.hs.web.command.admin.UserCommand;
import uk.co.hs.web.interceptor.TabsAccessibilityInterceptor;
import uk.co.hs.web.util.OptionDTO;

/**
 * UserEditController.
 */
@Controller("hs_userEditController")
@RequestMapping("/" + TabsAccessibilityInterceptor.USER_EDIT_URL)
@SessionAttributes(AdminGeneralConstants.ADMIN_COMMAND)
public class UserEditController extends AdminEditController
{
  @Resource
  private WebUserServiceInterface mUserService;

  @Resource
  private WebRoleServiceInterface mWebRoleService;

  @Resource
  private WebForwardingServiceInterface mWebForwardingService;

  @Resource
  private WebUrlServiceInterface mUrlService;


  @ModelAttribute("roles")
  protected List<OptionDTO> roles()
  {
    List<OptionDTO> list = new ArrayList<OptionDTO>();
    list.add(new OptionDTO("", ""));

    for (WebRole role : mWebRoleService.getAllWebRoles())
    {
      list.add(new OptionDTO(role.getPk().toString(), role.getName()));
    }
    return list;
  }

  @ModelAttribute("forwardingUrls")
  protected List<OptionDTO> forwardingUrls()
  {
    List<OptionDTO> list = new ArrayList<OptionDTO>();
    list.add(new OptionDTO("", ""));

    for (WebUrl url : mUrlService.getAllSortedByUrl())
    {
      if (url.getForwardableByDefault())
      {
        list.add(new OptionDTO(url.getPk().toString(), url.getDescription()));
      }
    }
    return list;
  }

  /**
   * Form Backing Object.
   *
   * @param aRequest HttpServletRequest.
   * @return ModelAndView.
   */
  @RequestMapping(method = RequestMethod.GET)
  protected ModelAndView formBackingObject(HttpServletRequest aRequest)
  {
    UserCommand command = new UserCommand();

    // Get logged on user's role
    String loggedOnUserName = SecurityContextHolder.getContext().getAuthentication().getName();
    if (loggedOnUserName != null)
    {
      WebUser loggedOnUser = mUserService.getWebUser(loggedOnUserName);
      if (loggedOnUser != null)
      {
      	command.setLoggedOnUserName(loggedOnUserName);

      	// Role
      	WebRole loggedOnUserRole = loggedOnUser.getRole();
        if (loggedOnUserRole != null)
        {
          command.setLoggedOnRoleName(loggedOnUserRole.getName());
        }
      }
    }

    // User clicked on
    String idParam = aRequest.getParameter("id_0");
    if (idParam == null || idParam.isEmpty())
    {
      command.setIsNew(Boolean.TRUE);
    }
    else
    {
      Long userId = new Long(idParam);
      command.setIsNew(Boolean.FALSE);

      WebUser userFromDb = mUserService.getWebUser(userId);

      // Role
      WebRole role = userFromDb.getRole();
      if (role != null)
      {
      	command.setRolePk(role.getPk());
      	command.setRoleName(role.getName());
      }

      // Forwarding URL
      WebForwarding webForwarding = mWebForwardingService.getWebForwarding(userFromDb.getUsername());
      if (webForwarding != null)
      {
        command.setForwardingUrlPk(webForwarding.getWebUrl().getPk());
      }

      command.setUser(userFromDb);
    }

    ModelAndView mav = new ModelAndView(getViewName());
    mav.addObject(AdminGeneralConstants.ADMIN_COMMAND, command);
    return mav;
  }

  /**
   * Save Detail.
   *
   * @param aRequest HttpServletRequest.
   * @param aCommand UserCommand.
   * @param aErrors Errors.
   * @return ModelAndView.
   */
  @RequestMapping(params = AdminGeneralConstants.ADMIN_REQUESTED_ACTION + "=save", method = RequestMethod.POST)
  public ModelAndView saveDetail(HttpServletRequest aRequest,
                                 @ModelAttribute(AdminGeneralConstants.ADMIN_COMMAND) UserCommand aCommand,
                                 Errors aErrors)
  {
    WebUser userFromCommand = aCommand.getUser();
    if (aCommand.getIsNew())
    {
      userFromCommand.setActive(true);
      userFromCommand.setLocked(false);
      userFromCommand.setNewPasswordRequired(true);
    }

    String errorMessage = null;
    String errorParam = null;
    try
    {
      errorMessage = mUserService.saveUserAndLinkRoleAndLinkFowarding(userFromCommand,
                                                                      aCommand.getRolePk(),
                                                                      aCommand.getForwardingUrlPk(),
                                                                      aCommand.getIsNew());
    }
    catch (DataIntegrityViolationException aException)
    {
      errorMessage = DataAccessExceptions.DATA_INTEGRITY_VIOLATION;
      errorParam = "User";
    }
    catch (HibernateOptimisticLockingFailureException aException)
    {
      errorMessage = DataAccessExceptions.ALREADY_UPDATED;
      errorParam = "User";
    }
    catch (DataAccessException aException)
    {
      errorMessage = DataAccessExceptions.DATA_ACCESS_FAILURE;
      errorParam = "User";
    }
    catch (Exception aException)
    {
      errorMessage = DataAccessExceptions.UNKNOWN;
      errorParam = aException.getMessage();

      aException.printStackTrace();
    }

    if (errorMessage != null)
    {
      aErrors.reject(errorMessage, new String[] {errorParam}, errorMessage);

      ModelAndView mav = new ModelAndView(getViewName());
      mav.addObject(AdminGeneralConstants.ADMIN_COMMAND, aCommand);
      return mav;
    }

    return getRedirectListView();
  }

  /**
   * Reset Password.
   *
   * @param aRequest HttpServletRequest.
   * @param aCommand UserCommand.
   * @param aErrors Errors.
   * @return ModelAndView.
   */
  @RequestMapping(params = AdminGeneralConstants.ADMIN_REQUESTED_ACTION + "=resetPassword", method = RequestMethod.POST)
  public ModelAndView resetPassword(HttpServletRequest aRequest,
                                    @ModelAttribute(AdminGeneralConstants.ADMIN_COMMAND) UserCommand aCommand,
                                    Errors aErrors)
  {
    WebUser userFromCommand = aCommand.getUser();

    String[] errorMessageAndNewPassword = new String[2];
    try
    {
      errorMessageAndNewPassword = mUserService.resetPassword(userFromCommand.getUsername());
    }
    catch (DataIntegrityViolationException aException)
    {
      errorMessageAndNewPassword[0] = DataAccessExceptions.DATA_INTEGRITY_VIOLATION;
      errorMessageAndNewPassword[1] = null;
    }
    catch (HibernateOptimisticLockingFailureException aException)
    {
      errorMessageAndNewPassword[0] = DataAccessExceptions.ALREADY_UPDATED;
      errorMessageAndNewPassword[1] = null;
    }
    catch (DataAccessException aException)
    {
      errorMessageAndNewPassword[0] = DataAccessExceptions.DATA_ACCESS_FAILURE;
      errorMessageAndNewPassword[1] = null;
    }
    catch (Exception aException)
    {
      errorMessageAndNewPassword[0] = DataAccessExceptions.UNKNOWN;
      errorMessageAndNewPassword[1] = null;
    }

    String errorMessage = errorMessageAndNewPassword[0];
    if (errorMessage != null)
    {
      aErrors.reject(errorMessage, new String[] {"Reset Password"}, errorMessage);
      ModelAndView mav = new ModelAndView(getViewName());
      aCommand.setShowNewPassword(Boolean.FALSE.toString());
      aCommand.setNewPassword(null);
      mav.addObject(AdminGeneralConstants.ADMIN_COMMAND, aCommand);
      return mav;
    }

    ModelAndView mav = new ModelAndView(getViewName());
    aCommand.setShowNewPassword(Boolean.TRUE.toString());
    aCommand.setNewPassword(errorMessageAndNewPassword[1]);
    mav.addObject(AdminGeneralConstants.ADMIN_COMMAND, aCommand);
    return mav;
  }

  /**
   * Cancel.
   *
   * @return ModelAndView.
   */
  @RequestMapping(params = AdminGeneralConstants.ADMIN_REQUESTED_ACTION + "=cancel", method = RequestMethod.POST)
  public ModelAndView cancel()
  {
    return getRedirectListView();
  }

  /**
   * Delete.
   *
   * @param aCommand UserCommand.
   * @return ModelAndView.
   */
  @RequestMapping(params = AdminGeneralConstants.ADMIN_REQUESTED_ACTION + "=delete", method = RequestMethod.POST)
  public ModelAndView delete(HttpServletRequest aRequest,
                             @ModelAttribute(AdminGeneralConstants.ADMIN_COMMAND) UserCommand aCommand,
                             Errors aErrors)
  {
    WebUser userFromCommand = aCommand.getUser();
    if (aCommand.getIsNew())
    {
      userFromCommand.setActive(Boolean.TRUE);
    }

    String errorMessage = null;
    try
    {
      mUserService.delete(userFromCommand);
    }
    catch (DataIntegrityViolationException aException)
    {
      errorMessage = DataAccessExceptions.DATA_INTEGRITY_VIOLATION;
    }
    catch (HibernateOptimisticLockingFailureException aException)
    {
      errorMessage = DataAccessExceptions.ALREADY_UPDATED;
    }
    catch (DataAccessException aException)
    {
      errorMessage = DataAccessExceptions.DATA_ACCESS_FAILURE;
    }
    catch (Exception aException)
    {
      errorMessage = DataAccessExceptions.UNKNOWN;
    }

    if (errorMessage != null)
    {
      aErrors.reject(errorMessage, new String[] {"User"}, errorMessage);
      ModelAndView mav = new ModelAndView(getViewName());
      mav.addObject(AdminGeneralConstants.ADMIN_COMMAND, aCommand);
      return mav;
    }

    return getRedirectListView();
  }

  public String getViewName()
  {
    return "hs_userEdit";
  }

  private ModelAndView getRedirectListView()
  {
    return new ModelAndView(new RedirectView(TabsAccessibilityInterceptor.USER_LIST_URL));
  }
}
